home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / idlelib / Debugger.py < prev    next >
Text File  |  2005-10-18  |  15KB  |  475 lines

  1. import os
  2. import bdb
  3. import types
  4. from Tkinter import *
  5. from WindowList import ListedToplevel
  6. from ScrolledList import ScrolledList
  7.  
  8.  
  9. class Idb(bdb.Bdb):
  10.  
  11.     def __init__(self, gui):
  12.         self.gui = gui
  13.         bdb.Bdb.__init__(self)
  14.  
  15.     def user_line(self, frame):
  16.         if self.in_rpc_code(frame):
  17.             self.set_step()
  18.             return
  19.         message = self.__frame2message(frame)
  20.         self.gui.interaction(message, frame)
  21.  
  22.     def user_exception(self, frame, info):
  23.         if self.in_rpc_code(frame):
  24.             self.set_step()
  25.             return
  26.         message = self.__frame2message(frame)
  27.         self.gui.interaction(message, frame, info)
  28.  
  29.     def in_rpc_code(self, frame):
  30.         if frame.f_code.co_filename.count('rpc.py'):
  31.             return True
  32.         else:
  33.             prev_frame = frame.f_back
  34.             if prev_frame.f_code.co_filename.count('Debugger.py'):
  35.                 # (that test will catch both Debugger.py and RemoteDebugger.py)
  36.                 return False
  37.             return self.in_rpc_code(prev_frame)
  38.  
  39.     def __frame2message(self, frame):
  40.         code = frame.f_code
  41.         filename = code.co_filename
  42.         lineno = frame.f_lineno
  43.         basename = os.path.basename(filename)
  44.         message = "%s:%s" % (basename, lineno)
  45.         if code.co_name != "?":
  46.             message = "%s: %s()" % (message, code.co_name)
  47.         return message
  48.  
  49.  
  50. class Debugger:
  51.  
  52.     vstack = vsource = vlocals = vglobals = None
  53.  
  54.     def __init__(self, pyshell, idb=None):
  55.         if idb is None:
  56.             idb = Idb(self)
  57.         self.pyshell = pyshell
  58.         self.idb = idb
  59.         self.frame = None
  60.         self.make_gui()
  61.         self.interacting = 0
  62.  
  63.     def run(self, *args):
  64.         try:
  65.             self.interacting = 1
  66.             return self.idb.run(*args)
  67.         finally:
  68.             self.interacting = 0
  69.  
  70.     def close(self, event=None):
  71.         if self.interacting:
  72.             self.top.bell()
  73.             return
  74.         if self.stackviewer:
  75.             self.stackviewer.close(); self.stackviewer = None
  76.         # Clean up pyshell if user clicked debugger control close widget.
  77.         # (Causes a harmless extra cycle through close_debugger() if user
  78.         # toggled debugger from pyshell Debug menu)
  79.         self.pyshell.close_debugger()
  80.         # Now close the debugger control window....
  81.         self.top.destroy()
  82.  
  83.     def make_gui(self):
  84.         pyshell = self.pyshell
  85.         self.flist = pyshell.flist
  86.         self.root = root = pyshell.root
  87.         self.top = top = ListedToplevel(root)
  88.         self.top.wm_title("Debug Control")
  89.         self.top.wm_iconname("Debug")
  90.         top.wm_protocol("WM_DELETE_WINDOW", self.close)
  91.         self.top.bind("<Escape>", self.close)
  92.         #
  93.         self.bframe = bframe = Frame(top)
  94.         self.bframe.pack(anchor="w")
  95.         self.buttons = bl = []
  96.         #
  97.         self.bcont = b = Button(bframe, text="Go", command=self.cont)
  98.         bl.append(b)
  99.         self.bstep = b = Button(bframe, text="Step", command=self.step)
  100.         bl.append(b)
  101.         self.bnext = b = Button(bframe, text="Over", command=self.next)
  102.         bl.append(b)
  103.         self.bret = b = Button(bframe, text="Out", command=self.ret)
  104.         bl.append(b)
  105.         self.bret = b = Button(bframe, text="Quit", command=self.quit)
  106.         bl.append(b)
  107.         #
  108.         for b in bl:
  109.             b.configure(state="disabled")
  110.             b.pack(side="left")
  111.         #
  112.         self.cframe = cframe = Frame(bframe)
  113.         self.cframe.pack(side="left")
  114.         #
  115.         if not self.vstack:
  116.             self.__class__.vstack = BooleanVar(top)
  117.             self.vstack.set(1)
  118.         self.bstack = Checkbutton(cframe,
  119.             text="Stack", command=self.show_stack, variable=self.vstack)
  120.         self.bstack.grid(row=0, column=0)
  121.         if not self.vsource:
  122.             self.__class__.vsource = BooleanVar(top)
  123.         self.bsource = Checkbutton(cframe,
  124.             text="Source", command=self.show_source, variable=self.vsource)
  125.         self.bsource.grid(row=0, column=1)
  126.         if not self.vlocals:
  127.             self.__class__.vlocals = BooleanVar(top)
  128.             self.vlocals.set(1)
  129.         self.blocals = Checkbutton(cframe,
  130.             text="Locals", command=self.show_locals, variable=self.vlocals)
  131.         self.blocals.grid(row=1, column=0)
  132.         if not self.vglobals:
  133.             self.__class__.vglobals = BooleanVar(top)
  134.         self.bglobals = Checkbutton(cframe,
  135.             text="Globals", command=self.show_globals, variable=self.vglobals)
  136.         self.bglobals.grid(row=1, column=1)
  137.         #
  138.         self.status = Label(top, anchor="w")
  139.         self.status.pack(anchor="w")
  140.         self.error = Label(top, anchor="w")
  141.         self.error.pack(anchor="w", fill="x")
  142.         self.errorbg = self.error.cget("background")
  143.         #
  144.         self.fstack = Frame(top, height=1)
  145.         self.fstack.pack(expand=1, fill="both")
  146.         self.flocals = Frame(top)
  147.         self.flocals.pack(expand=1, fill="both")
  148.         self.fglobals = Frame(top, height=1)
  149.         self.fglobals.pack(expand=1, fill="both")
  150.         #
  151.         if self.vstack.get():
  152.             self.show_stack()
  153.         if self.vlocals.get():
  154.             self.show_locals()
  155.         if self.vglobals.get():
  156.             self.show_globals()
  157.  
  158.     def interaction(self, message, frame, info=None):
  159.         self.frame = frame
  160.         self.status.configure(text=message)
  161.         #
  162.         if info:
  163.             type, value, tb = info
  164.             try:
  165.                 m1 = type.__name__
  166.             except AttributeError:
  167.                 m1 = "%s" % str(type)
  168.             if value is not None:
  169.                 try:
  170.                     m1 = "%s: %s" % (m1, str(value))
  171.                 except:
  172.                     pass
  173.             bg = "yellow"
  174.         else:
  175.             m1 = ""
  176.             tb = None
  177.             bg = self.errorbg
  178.         self.error.configure(text=m1, background=bg)
  179.         #
  180.         sv = self.stackviewer
  181.         if sv:
  182.             stack, i = self.idb.get_stack(self.frame, tb)
  183.             sv.load_stack(stack, i)
  184.         #
  185.         self.show_variables(1)
  186.         #
  187.         if self.vsource.get():
  188.             self.sync_source_line()
  189.         #
  190.         for b in self.buttons:
  191.             b.configure(state="normal")
  192.         #
  193.         self.top.wakeup()
  194.         self.root.mainloop()
  195.         #
  196.         for b in self.buttons:
  197.             b.configure(state="disabled")
  198.         self.status.configure(text="")
  199.         self.error.configure(text="", background=self.errorbg)
  200.         self.frame = None
  201.  
  202.     def sync_source_line(self):
  203.         frame = self.frame
  204.         if not frame:
  205.             return
  206.         filename, lineno = self.__frame2fileline(frame)
  207.         if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
  208.             self.flist.gotofileline(filename, lineno)
  209.  
  210.     def __frame2fileline(self, frame):
  211.         code = frame.f_code
  212.         filename = code.co_filename
  213.         lineno = frame.f_lineno
  214.         return filename, lineno
  215.  
  216.     def cont(self):
  217.         self.idb.set_continue()
  218.         self.root.quit()
  219.  
  220.     def step(self):
  221.         self.idb.set_step()
  222.         self.root.quit()
  223.  
  224.     def next(self):
  225.         self.idb.set_next(self.frame)
  226.         self.root.quit()
  227.  
  228.     def ret(self):
  229.         self.idb.set_return(self.frame)
  230.         self.root.quit()
  231.  
  232.     def quit(self):
  233.         self.idb.set_quit()
  234.         self.root.quit()
  235.  
  236.     stackviewer = None
  237.  
  238.     def show_stack(self):
  239.         if not self.stackviewer and self.vstack.get():
  240.             self.stackviewer = sv = StackViewer(self.fstack, self.flist, self)
  241.             if self.frame:
  242.                 stack, i = self.idb.get_stack(self.frame, None)
  243.                 sv.load_stack(stack, i)
  244.         else:
  245.             sv = self.stackviewer
  246.             if sv and not self.vstack.get():
  247.                 self.stackviewer = None
  248.                 sv.close()
  249.             self.fstack['height'] = 1
  250.  
  251.     def show_source(self):
  252.         if self.vsource.get():
  253.             self.sync_source_line()
  254.  
  255.     def show_frame(self, (frame, lineno)):
  256.         self.frame = frame
  257.         self.show_variables()
  258.  
  259.     localsviewer = None
  260.     globalsviewer = None
  261.  
  262.     def show_locals(self):
  263.         lv = self.localsviewer
  264.         if self.vlocals.get():
  265.             if not lv:
  266.                 self.localsviewer = NamespaceViewer(self.flocals, "Locals")
  267.         else:
  268.             if lv:
  269.                 self.localsviewer = None
  270.                 lv.close()
  271.                 self.flocals['height'] = 1
  272.         self.show_variables()
  273.  
  274.     def show_globals(self):
  275.         gv = self.globalsviewer
  276.         if self.vglobals.get():
  277.             if not gv:
  278.                 self.globalsviewer = NamespaceViewer(self.fglobals, "Globals")
  279.         else:
  280.             if gv:
  281.                 self.globalsviewer = None
  282.                 gv.close()
  283.                 self.fglobals['height'] = 1
  284.         self.show_variables()
  285.  
  286.     def show_variables(self, force=0):
  287.         lv = self.localsviewer
  288.         gv = self.globalsviewer
  289.         frame = self.frame
  290.         if not frame:
  291.             ldict = gdict = None
  292.         else:
  293.             ldict = frame.f_locals
  294.             gdict = frame.f_globals
  295.             if lv and gv and ldict is gdict:
  296.                 ldict = None
  297.         if lv:
  298.             lv.load_dict(ldict, force, self.pyshell.interp.rpcclt)
  299.         if gv:
  300.             gv.load_dict(gdict, force, self.pyshell.interp.rpcclt)
  301.  
  302.     def set_breakpoint_here(self, filename, lineno):
  303.         self.idb.set_break(filename, lineno)
  304.  
  305.     def clear_breakpoint_here(self, filename, lineno):
  306.         self.idb.clear_break(filename, lineno)
  307.  
  308.     def clear_file_breaks(self, filename):
  309.         self.idb.clear_all_file_breaks(filename)
  310.  
  311.     def load_breakpoints(self):
  312.         "Load PyShellEditorWindow breakpoints into subprocess debugger"
  313.         pyshell_edit_windows = self.pyshell.flist.inversedict.keys()
  314.         for editwin in pyshell_edit_windows:
  315.             filename = editwin.io.filename
  316.             try:
  317.                 for lineno in editwin.breakpoints:
  318.                     self.set_breakpoint_here(filename, lineno)
  319.             except AttributeError:
  320.                 continue
  321.  
  322. class StackViewer(ScrolledList):
  323.  
  324.     def __init__(self, master, flist, gui):
  325.         ScrolledList.__init__(self, master, width=80)
  326.         self.flist = flist
  327.         self.gui = gui
  328.         self.stack = []
  329.  
  330.     def load_stack(self, stack, index=None):
  331.         self.stack = stack
  332.         self.clear()
  333.         for i in range(len(stack)):
  334.             frame, lineno = stack[i]
  335.             try:
  336.                 modname = frame.f_globals["__name__"]
  337.             except:
  338.                 modname = "?"
  339.             code = frame.f_code
  340.             filename = code.co_filename
  341.             funcname = code.co_name
  342.             import linecache
  343.             sourceline = linecache.getline(filename, lineno)
  344.             import string
  345.             sourceline = string.strip(sourceline)
  346.             if funcname in ("?", "", None):
  347.                 item = "%s, line %d: %s" % (modname, lineno, sourceline)
  348.             else:
  349.                 item = "%s.%s(), line %d: %s" % (modname, funcname,
  350.                                                  lineno, sourceline)
  351.             if i == index:
  352.                 item = "> " + item
  353.             self.append(item)
  354.         if index is not None:
  355.             self.select(index)
  356.  
  357.     def popup_event(self, event):
  358.         "override base method"
  359.         if self.stack:
  360.             return ScrolledList.popup_event(self, event)
  361.  
  362.     def fill_menu(self):
  363.         "override base method"
  364.         menu = self.menu
  365.         menu.add_command(label="Go to source line",
  366.                          command=self.goto_source_line)
  367.         menu.add_command(label="Show stack frame",
  368.                          command=self.show_stack_frame)
  369.  
  370.     def on_select(self, index):
  371.         "override base method"
  372.         if 0 <= index < len(self.stack):
  373.             self.gui.show_frame(self.stack[index])
  374.  
  375.     def on_double(self, index):
  376.         "override base method"
  377.         self.show_source(index)
  378.  
  379.     def goto_source_line(self):
  380.         index = self.listbox.index("active")
  381.         self.show_source(index)
  382.  
  383.     def show_stack_frame(self):
  384.         index = self.listbox.index("active")
  385.         if 0 <= index < len(self.stack):
  386.             self.gui.show_frame(self.stack[index])
  387.  
  388.     def show_source(self, index):
  389.         if not (0 <= index < len(self.stack)):
  390.             return
  391.         frame, lineno = self.stack[index]
  392.         code = frame.f_code
  393.         filename = code.co_filename
  394.         if os.path.isfile(filename):
  395.             edit = self.flist.open(filename)
  396.             if edit:
  397.                 edit.gotoline(lineno)
  398.  
  399.  
  400. class NamespaceViewer:
  401.  
  402.     def __init__(self, master, title, dict=None):
  403.         width = 0
  404.         height = 40
  405.         if dict:
  406.             height = 20*len(dict) # XXX 20 == observed height of Entry widget
  407.         self.master = master
  408.         self.title = title
  409.         import repr
  410.         self.repr = repr.Repr()
  411.         self.repr.maxstring = 60
  412.         self.repr.maxother = 60
  413.         self.frame = frame = Frame(master)
  414.         self.frame.pack(expand=1, fill="both")
  415.         self.label = Label(frame, text=title, borderwidth=2, relief="groove")
  416.         self.label.pack(fill="x")
  417.         self.vbar = vbar = Scrollbar(frame, name="vbar")
  418.         vbar.pack(side="right", fill="y")
  419.         self.canvas = canvas = Canvas(frame,
  420.                                       height=min(300, max(40, height)),
  421.                                       scrollregion=(0, 0, width, height))
  422.         canvas.pack(side="left", fill="both", expand=1)
  423.         vbar["command"] = canvas.yview
  424.         canvas["yscrollcommand"] = vbar.set
  425.         self.subframe = subframe = Frame(canvas)
  426.         self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw")
  427.         self.load_dict(dict)
  428.  
  429.     dict = -1
  430.  
  431.     def load_dict(self, dict, force=0, rpc_client=None):
  432.         if dict is self.dict and not force:
  433.             return
  434.         subframe = self.subframe
  435.         frame = self.frame
  436.         for c in subframe.children.values():
  437.             c.destroy()
  438.         self.dict = None
  439.         if not dict:
  440.             l = Label(subframe, text="None")
  441.             l.grid(row=0, column=0)
  442.         else:
  443.             names = dict.keys()
  444.             names.sort()
  445.             row = 0
  446.             for name in names:
  447.                 value = dict[name]
  448.                 svalue = self.repr.repr(value) # repr(value)
  449.                 # Strip extra quotes caused by calling repr on the (already)
  450.                 # repr'd value sent across the RPC interface:
  451.                 if rpc_client:
  452.                     svalue = svalue[1:-1]
  453.                 l = Label(subframe, text=name)
  454.                 l.grid(row=row, column=0, sticky="nw")
  455.                 l = Entry(subframe, width=0, borderwidth=0)
  456.                 l.insert(0, svalue)
  457.                 l.grid(row=row, column=1, sticky="nw")
  458.                 row = row+1
  459.         self.dict = dict
  460.         # XXX Could we use a <Configure> callback for the following?
  461.         subframe.update_idletasks() # Alas!
  462.         width = subframe.winfo_reqwidth()
  463.         height = subframe.winfo_reqheight()
  464.         canvas = self.canvas
  465.         self.canvas["scrollregion"] = (0, 0, width, height)
  466.         if height > 300:
  467.             canvas["height"] = 300
  468.             frame.pack(expand=1)
  469.         else:
  470.             canvas["height"] = height
  471.             frame.pack(expand=0)
  472.  
  473.     def close(self):
  474.         self.frame.destroy()
  475.